﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Text.RegularExpressions;
using System.ComponentModel;
using System.Xml;

namespace Nizm0.QOT.Library.Objects
{
    [Serializable]
    [XmlInclude(typeof(ProcedureVersion))]
    [XmlRoot("Procedure")]
    //[XmlInclude(typeof(ProcedureFromDatabase))]
    //[XmlInclude(typeof(VariableInTheProcedure))]
    public abstract class Procedure : IProcedure, ISettingsObjects, IProcedureDetails, IXmlSerializable//, IProcedureInfo
    {
        public Procedure() { Source = "Empty Constructor"; }
        public Procedure(string name)
        {
            Name = name;
            Source = "Empty Constructor"; 
        }

        [XmlIgnore()]
        public string Source { get; set; }
        [XmlIgnore()]
        private IProcedureInfo _parent;
        private bool _loadedFromSettings = false;
        [XmlIgnore()]
        public bool LoadedFromSettings
        {
            get { return _loadedFromSettings; }
            set { _loadedFromSettings = value; }
        }

        public enum EnumProcType { Old, New, Unknown, None }
        public enum EnumSource { Database, File, App};
        [Flags]
        public enum EnumActionInProcedure
        {
            None = 0x0,         //(00000000)
            Update = 0x1,       //(00000001)
            Insert = 0x2,       //(00000010)
            Transaction = 0x4,  //(00000100)
            Declare = 0x8,      //(00001000)
            Delete = 0x10,      //(00010000)
            Select = 0x20       //(00100000)
            //(01000000)
            //(10000000)
        }

        [XmlIgnore()]
        public IProcedureInfo Parent
        {
            get { return _parent; }
            set { _parent = value; }
        }

        #region Delegates

        public static event ChangeStatusEvetHendler StatusChange;

        public static event ErrorEventHandler ErrorEvent;

        public static void SetStatusChangeEvent(ChangeStatusEvetHendler test)
        {
            if (StatusChange == null)
                StatusChange += test;
        }

        public static void SetErrorEvent(ErrorEventHandler test)
        {
            if (ErrorEvent == null)
                ErrorEvent += test;
        }

        public event VersionChangeEventHandler VersionChange;

        public void OnVersionChange(object sender, VersionChangeEventArgs e)
        {
            if (VersionChange != null)
                VersionChange(sender, e);
        }
        #endregion

        #region IProcedure Members

        [XmlAttribute("Name")]
        public string Name { get; set; }

        private DateTime _creationTime;
        [XmlAttribute("Creationtime")]
        public DateTime CreationTime
        {
            get { return _creationTime; }
            set { _creationTime = value; }
        }

        private DateTime _modifiedtime;
        [XmlAttribute("Modifiedtime")]
        public DateTime ModifiedTime
        {
            get { return _modifiedtime; }
            set { _modifiedtime = value; }
        }

        [XmlIgnore]
        private Procedure.EnumActionInProcedure _actionInProcedure;

        [XmlAttribute("ActionInProcedure")]
        public Procedure.EnumActionInProcedure ActionInProcedure
        {
            get { return _actionInProcedure; }
            set { _actionInProcedure = value; }
        }

        [NonSerialized]
        [XmlIgnore]
        private List<VariableInTheProcedure> _listOfVariable = new List<VariableInTheProcedure>();

        [NonSerialized]
        [XmlIgnore]
        private Procedure.EnumProcType _type = EnumProcType.None;

        [XmlIgnore]
        public List<VariableInTheProcedure> ListOfVariable
        {
            get { return _listOfVariable; }
            set { _listOfVariable = value; }
        }

        //[XmlArray("ProcedureVersions"), XmlArrayItem("ProcedureVersion", typeof(ProcedureVersion))]
        [XmlIgnore]
        public List<ProcedureVersion> ProcVersionList
        {
            get { return _procVersionList; }
            set { _procVersionList = value; }
        }

        [XmlIgnore]
        public Procedure.EnumSource SourceType
        {
            get;
            set;
        }
        [XmlAttribute("Type")]
        public Procedure.EnumProcType Type
        {
            get { return _type; }
            set { _type = value; }
        }

        [XmlIgnore()]
        public virtual string Text
        {
            get;
            set;
        }
        //protected string _version;
        protected ProcedureVersion _version;
        [XmlElement("Version", typeof(ProcedureVersion))]
        public ProcedureVersion Version
        {
            get
            {
                lock (this)
                {
                    if (_procVersionList != null && _procVersionList.Count > 0)
                    {
                        _version = _procVersionList[0];
                        _version.Parent = this;
                        _version.Hash = this.Hash;
                        return _version;
                    }
                    else
                        return null;
                }
            }
            private set
            {
                _version = value;
                if (!ProcVersionList.Exists(v => v.Version == _version.Version))
                    ProcVersionList.Add(_version);
                else
                {
                    ProcVersionList.RemoveAll(v => v.Version == _version.Version);
                    ProcVersionList.Add(_version);
                }
            }
        }
        protected string _versionString;
        [XmlAttribute("Version")]
        public string VersionString
        {
            get
            {
                _versionString = Version.Version;
                return _versionString;
            }
            set
            {
                _versionString = value;
            }
        }

        protected string _hash;// = string.Empty;
        [XmlAttribute("Hash")]
        public string Hash
        {
            get { return _hash; }
            set { _hash = value; }
        }

        [XmlAttribute("Location")]
        public virtual string Location
        {
            get;
            set;
        }

        [NonSerialized]
        [XmlIgnore()]
        protected System.Windows.Forms.UserControl _ucProcedure;
        private List<ProcedureVersion> _procVersionList = new List<ProcedureVersion>();

        #endregion

        #region IProcedureDetails Members

        [XmlIgnore]
        Procedure.EnumActionInProcedure IProcedureDetails.ActionInProcedure
        {
            get { return _actionInProcedure; }
            set { _actionInProcedure = value; }
        }

        [XmlIgnore]
        List<VariableInTheProcedure> IProcedureDetails.Variables
        {
            get
            {
                return _listOfVariable;
            }
            set
            {
                _listOfVariable = value;
            }
        }

        void IProcedureDetails.GetParameters(string str)
        {
            throw new NotImplementedException();
        }

        IProcedureInfo IProcedureDetails.GetProcedure()
        {
            throw new NotImplementedException();
        }

        public void Marge(ISettingsObjects procedure)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region ISettingsObjects Members


        [XmlIgnore]
        public int Treelevel
        {
            get;
            set;
        }

        [XmlIgnore]
        public bool Checked
        {
            get;
            set;
        }

        #endregion

        //#region IProcedureInfo Members

        //[XmlIgnore]
        //string IProcedureInfo.Name
        //{
        //    get
        //    {
        //        return Name;
        //    }
        //    set
        //    {
        //        Name = value;
        //    }
        //}

        //IProcedureInfo IProcedureInfo.GetProcedure()
        //{
        //    throw new NotImplementedException();
        //}

        //#endregion

        //[XmlIgnore()]//"--\s*(V|v|ver|VER|Ver)([\.\-\\\s])*(?<Ver>([0-9]{1,3})([\.\-\\\s])([0-9]{1,3})([\.\-\\\s])([0-9]{1,3}))"
        //protected string[] pattenrntab = Settings.Instance.PaternList.FindAll(p => p.Group == "procedure").ToArray();
                                //{@"--\s*(V|v|ver|VER|Ver)([\.\-\\\s])*(?<Ver>([0-9]{1,3})([\.\-\\\s])([0-9]{1,3})([\.\-\\\s])([0-9]{1,3}))[\s\|]*(?<Data>[0-9]{4}-[0-9]{2}-[0-9]{2})[\s\|]*(?<Project>[^\||^\s|^\r]+)[\s\|\s]*(?<User>[A-Z]{1}[^\s]*\s[A-Z]{1}[^\s|\|]*){0,}[\s\|\s]*(?<Comment>[^\r]+)",
                                //"(V|v|ver|VER|Ver)\\.*\\s*(?<Ver>([0-9]{1,3}(\\.)*)+)[\\s\\|\\s]*(?<Data>[0-9]{4}-[0-9]{2}-[0-9]{2})[\\s\\|\\s]*(?<Project>[^\\||^\\s|^\\r]+)[\\s\\|\\s]*(?<User>[A-Z]{1}[^\\s]*\\s[A-Z]{1}[^\\s|\\|]*){0,}[\\s\\|\\s]*(?<Comment>[^\\r]+)",
                                //@"--\s*(?<Ver>([0-9]{1,3}(\.)*)+)[\s\|]*(?<Data>[0-9]{4}-[0-9]{2}-[0-9]{2})[\s\|]*(?<Project>[^\||^\s|^\r]+)[\s\|]*(?<User>[A-Z]{1}[^\s]*\s[A-Z]{1}[^\s|\|]*){0,}[\s\|\s]*(?<Comment>[^\r]+)"
                                //};
        #region Methods

        /// <summary>
        /// Get information on procedure, like:
        /// Data Create, Any updatets or inserts in Database Table, number of version
        /// </summary>
        protected void GetInfoOfProcedure()
        {
            if (string.IsNullOrWhiteSpace(Text))
                System.Windows.Forms.MessageBox.Show("First press \"Get\" button.", "Warning!", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Asterisk);
            else
                GetInfoOfProcedure(Text);
        }

        /// <summary>
        /// verify information on procedure, like:
        /// Data Create, Any updatets or inserts in Database Table, number of version
        /// </summary>
        public void GetInfoOfProcedure(string text)
        {
            //_hashcode = text.GetHashCode();
            string pattern = "update\\s\\[*[a-zA-Z]*";

            if (Regex.IsMatch(text, pattern, RegexOptions.IgnoreCase))
            {
                _actionInProcedure = _actionInProcedure | Procedure.EnumActionInProcedure.Update;
                //IsUpdate = true;
                int position = text.IndexOf("update");
                //_bodyofprocedure[position + 7];
                string[] tab = Regex.Split(text, pattern, RegexOptions.IgnoreCase);
            }

            pattern = "insert\\s\\[*[a-zA-Z]*";

            if (Regex.IsMatch(text, pattern, RegexOptions.IgnoreCase))
            {
                _actionInProcedure = _actionInProcedure | Procedure.EnumActionInProcedure.Insert;
                //IsInsert = true;
                int position = text.IndexOf("insert");
                //_bodyofprocedure[position + 7];
                string[] tab = Regex.Split(text, pattern, RegexOptions.IgnoreCase);
            }

            pattern = "begin\\stran";

            if (Regex.IsMatch(text, pattern, RegexOptions.IgnoreCase))
            {
                _actionInProcedure = _actionInProcedure | Procedure.EnumActionInProcedure.Transaction;
                //IsTransaction = true;
                int position = text.IndexOf("begin tran");
                //_bodyofprocedure[position + 7];
                string[] tab = Regex.Split(text, pattern, RegexOptions.IgnoreCase);
            }

            pattern = "delete\\s\\[*[a-zA-Z]*";

            if (Regex.IsMatch(text, pattern, RegexOptions.IgnoreCase))
            {
                _actionInProcedure = _actionInProcedure | Procedure.EnumActionInProcedure.Delete;
                //IsDelete = true;
                int position = text.IndexOf("delete");
                //_bodyofprocedure[position + 7];
                string[] tab = Regex.Split(text, pattern, RegexOptions.IgnoreCase);
            }

            pattern = "select\\s\\[*[a-zA-Z]*";

            if (Regex.IsMatch(text, pattern, RegexOptions.IgnoreCase))
            {
                _actionInProcedure = _actionInProcedure | Procedure.EnumActionInProcedure.Select;
                //IsDelete = true;
                int position = text.IndexOf("select");
                //_bodyofprocedure[position + 7];
                string[] tab = Regex.Split(text, pattern, RegexOptions.IgnoreCase);
            }

            //_procVersionList.AddRange(GetVersions(text));
            foreach (ProcedureVersion tmpver in GetVersions(text))
            {
                AddNewVersion(tmpver);
            }
            
            _procVersionList.Sort(delegate(ProcedureVersion pv1, ProcedureVersion pv2)
            {
                if (pv1.Version == ProcedureVersion.Unknown || pv2.Version == ProcedureVersion.Unknown)
                    return pv1.Date.CompareTo(pv2.Date);
                //return pv1.Version.CompareTo(pv2.Version);
                return pv1.CompareTo(pv2);
            });
        }

        private void AddNewVersion(ProcedureVersion version)
        {
            if (!_procVersionList.Exists(v => v.Version == version.Version))
            {
                _procVersionList.Add(version);
            }
        }

        /// <summary>
        /// Read versions of the content of the procedure, if it has been set
        /// </summary>
        /// <returns></returns>
        public List<ProcedureVersion> GetVersions()
        {
            List<string> pattenrntab = new List<string>();
            foreach (RegexPatern rp in Settings.Instance.PaternList.FindAll(p => p.Group == "procedure"))
            {
                pattenrntab.Add(rp.Pattern);
            }
            return GetVersions(Text, pattenrntab.ToArray());
        }

        /// <summary>
        /// Read versions of the text
        /// </summary>
        /// <returns></returns>
        public List<ProcedureVersion> GetVersions(string text)
        {
            List<string> pattenrntab = new List<string>();
            foreach (RegexPatern rp in Settings.Instance.PaternList.FindAll(p => p.Group == "procedure"))
            {
                pattenrntab.Add(rp.Pattern);
            }
            return GetVersions(text, pattenrntab.ToArray());
        }

        /// <summary>
        /// Read versions of textu, using given pattern
        /// </summary>
        /// <returns></returns>
        public List<ProcedureVersion> GetVersions(string text, string[] pattern)
        {
            List<ProcedureVersion> tmplist = new List<ProcedureVersion>();
            //pattern = "(v|ver)\\.*\\s*(?<Ver>([0-9](\\.|^\\s)*)+)\\s*\\|\\s*(?<Data>[0-9]{4}-[0-9]{2}-[0-9]{2})\\s*\\|\\s*(?<Project>[^\\|]+)\\s*\\|\\s*(?<User>[^\\|]+)\\s*\\|\\s*(?<Comment>[^\\|]+)\\n";
            foreach (RegexPatern rp in Settings.Instance.PaternList.FindAll(p => p.Group == "procedure"))
            {
                foreach (Match match in Regex.Matches(text, rp.Pattern))
                {
                    ProcedureVersion ver = new ProcedureVersion(match);
                    ver.Parent = this;
                    if (!tmplist.Exists(v => v.Version == ver.Version))
                        tmplist.Add(ver);
                }
            }
            if (tmplist.Count == 0 && !_procVersionList.Exists(v => v.Version == ProcedureVersion.Unknown))
            {
                ProcedureVersion ver = new ProcedureVersion(ProcedureVersion.Unknown);
                ver.Parent = this;
                ver.Date = this.ModifiedTime;
                if (!tmplist.Exists(v => v.Version == ver.Version) && !tmplist.Exists(v => v.Date == ver.Date))
                    tmplist.Add(ver);
                //procver.Add(new ProcedureVersion("Unknown"));
            }

            tmplist.Sort(delegate(ProcedureVersion pv1, ProcedureVersion pv2)
            {
                if (pv1.Version == ProcedureVersion.Unknown || pv2.Version == ProcedureVersion.Unknown)
                    return pv1.Date.CompareTo(pv2.Date);
                //return pv1.Version.CompareTo(pv2.Version);
                return pv1.CompareTo(pv2);
            });
            return tmplist;
        }

        /// <summary>
        /// Retrieves information about the input parameters
        /// </summary>
        protected List<VariableInTheProcedure> GetParameters()
        {
            return ListOfVariable = GetParameters(Text);
        }

        /// <summary>
        /// Retrieves information about the input parameters from procedure text
        /// </summary>
        public List<VariableInTheProcedure> GetParameters(string str)
        {
            List<VariableInTheProcedure> tmpvariablelist = new List<VariableInTheProcedure>();
            try
            {
                //string tmptesttest = Name;
                string[] splitparameters = { "\r\n" };
                string[] rowsofbodyofprocedure = str.Split(splitparameters, StringSplitOptions.RemoveEmptyEntries);

                int startline = 0, endline = 0;
                int i = 0;
                do
                {
                    //a = _bodyofprocedure.IndexOf("alter procedure", StringComparison.CurrentCultureIgnoreCase);
                    int a1, a2, b, c;
                    a1 = rowsofbodyofprocedure[i].IndexOf("alter", StringComparison.CurrentCultureIgnoreCase);
                    a2 = rowsofbodyofprocedure[i].IndexOf("create", StringComparison.CurrentCultureIgnoreCase);
                    b = rowsofbodyofprocedure[i].IndexOf("exec", StringComparison.CurrentCultureIgnoreCase);
                    c = rowsofbodyofprocedure[i].IndexOf("--", 0);
                    if ((a1 >= 0 || a2 >= 0)
                        && (b < 0)
                        && (c < 0))
                        startline = i;
                    //else
                    //    if (rowsofbodyofprocedure[i].IndexOf("create", StringComparison.CurrentCultureIgnoreCase) > 0) startline = i;
                    i++;
                } while (startline == 0 && i < rowsofbodyofprocedure.Length);
                i = startline;
                do
                {
                    if (rowsofbodyofprocedure[i].IndexOf("as", StringComparison.CurrentCultureIgnoreCase) >= 0 && !rowsofbodyofprocedure[i].Contains("@"))
                    {
                        string tmprow = rowsofbodyofprocedure[i].Trim();
                        int tmppoz = tmprow.IndexOf("as", StringComparison.CurrentCultureIgnoreCase);
                        if (tmppoz - 1 < 0 && tmppoz + 2 >= tmprow.Length)
                            endline = i;
                        //else
                        //    if ((tmprow[tmppoz - 1] == '\r' || tmprow[tmppoz - 1] == '\n' || tmprow[tmppoz - 1] == '\t' || tmprow[tmppoz - 1] == ' ') &&
                        //    (tmprow[tmppoz + 2] == '\r' || tmprow[tmppoz + 2] == '\n' || tmprow[tmppoz + 2] == '\t' || tmprow[tmppoz + 2] == ' '))
                        //        endline = i;
                    }
                    i++;
                } while (endline == 0 && i < rowsofbodyofprocedure.Length);
                // get variable
                for (i = startline + 1; i < endline; i++)
                {
                    if (rowsofbodyofprocedure[i].Contains("@"))
                    {
                        string tmpcomment = null;
                        string teststring = null;
                        if (rowsofbodyofprocedure[i].Contains("--"))
                        {
                            tmpcomment = rowsofbodyofprocedure[i].Remove(0, rowsofbodyofprocedure[i].IndexOf("--") + 2).Trim();
                            teststring = rowsofbodyofprocedure[i].Remove(rowsofbodyofprocedure[i].IndexOf("--")).Trim();
                        }
                        else
                        {
                            teststring = rowsofbodyofprocedure[i].Trim();
                            tmpcomment = null;
                        }
                        bool end = false;
                        while (!end && !string.IsNullOrWhiteSpace(teststring))
                        {
                            int index = teststring.IndexOf(',');
                            string tmpstrvarrow = null;
                            if (teststring.IndexOf('(') < index)
                            {
                                if (teststring.IndexOf('(') > 0)
                                {
                                    index = teststring.IndexOf(',', teststring.IndexOf(')'));
                                    if (index > 0)
                                        tmpstrvarrow = teststring.Remove(index);
                                    else
                                    {
                                        tmpstrvarrow = teststring;
                                        end = true;
                                    }
                                }
                                else
                                    tmpstrvarrow = teststring.Remove(index);
                            }
                            else
                            {
                                if (index < 0)
                                {
                                    tmpstrvarrow = teststring;//.Remove(teststring.IndexOf(','));
                                    end = true;
                                }
                                else
                                    tmpstrvarrow = teststring.Remove(teststring.IndexOf(','));
                            }
                            if (index == teststring.LastIndexOf(','))
                            {
                                end = true;
                            }
                            else
                            {
                                if (index > 0)
                                    teststring = teststring.Remove(0, index);
                                else
                                {
                                    teststring = null;
                                    end = true;
                                }
                            }
                            if (!string.IsNullOrWhiteSpace(tmpstrvarrow))
                            {
                                //IMPORTAND (solve) Error with parameters like decimall like decimal(5,2)
                                string tmp2strvarrow = tmpstrvarrow.Remove(0, tmpstrvarrow.IndexOf('@'));
                                Objects.VariableInTheProcedure tmpvariable = new Objects.VariableInTheProcedure(new Variable(), tmp2strvarrow.Trim());

                                if (string.IsNullOrWhiteSpace(tmpvariable.Comment) && !string.IsNullOrWhiteSpace(tmpcomment))
                                    tmpvariable.Comment = tmpcomment;

                                if (!tmpvariablelist.Exists((Predicate<Objects.IVariable>)delegate
                                {
                                    foreach (Objects.VariableInTheProcedure test in tmpvariablelist)
                                    {
                                        if (test.Name == tmpvariable.Name) return true;
                                    }
                                    return false;
                                }))
                                {
                                    tmpvariablelist.Add(tmpvariable);
                                }
                                else
                                {
                                    index = 0;
                                    foreach (Objects.VariableInTheProcedure text in tmpvariablelist)
                                    {
                                        foreach (Objects.VariableInTheProcedure test in tmpvariablelist)
                                        {
                                            if (test.Name == tmpvariable.Name) index = tmpvariablelist.IndexOf(test);
                                        }
                                    }
                                    //if (_variables.Count <= i)
                                    //    _variables.RemoveAt(i-1);
                                }
                            }
                        }

                        //foreach (string tmpstrvarrow in teststring.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                        //{
                        //    if (!string.IsNullOrWhiteSpace(tmpstrvarrow))
                        //    {
                        //        string tmp2strvarrow = tmpstrvarrow.Remove(0, tmpstrvarrow.IndexOf('@'));
                        //        Objects.VariableInTheProcedure tmpvariable = new Objects.VariableInTheProcedure(new Variable(), tmp2strvarrow.Trim());

                        //        if (string.IsNullOrWhiteSpace(tmpvariable.Comment) && !string.IsNullOrWhiteSpace(tmpcomment))
                        //            tmpvariable.Comment = tmpcomment;

                        //        if (!tmpvariablelist.Exists((Predicate<Objects.IVariable>)delegate
                        //        {
                        //            foreach (Objects.VariableInTheProcedure test in tmpvariablelist)
                        //            {
                        //                if (test.Name == tmpvariable.Name) return true;
                        //            }
                        //            return false;
                        //        }))
                        //        {
                        //            tmpvariablelist.Add(tmpvariable);
                        //        }
                        //        else
                        //        {
                        //            int index = 0;
                        //            foreach (Objects.VariableInTheProcedure text in tmpvariablelist)
                        //            {
                        //                foreach (Objects.VariableInTheProcedure test in tmpvariablelist)
                        //                {
                        //                    if (test.Name == tmpvariable.Name) index = tmpvariablelist.IndexOf(test);
                        //                }
                        //            }
                        //            //if (_variables.Count <= i)
                        //            //    _variables.RemoveAt(i-1);
                        //        } 
                        //    }
                        //}
                    }
                }
                return tmpvariablelist;
            }
            catch (Exception ex)
            {
                //if (ErrorEvent != null) ErrorEvent(this, ex);
                //MessageBox.Show(ex.ToString());
                return null;
            }
            finally
            {

            }
        }

        public virtual System.Windows.Forms.UserControl Show()
        {

            return Show(new System.Windows.Forms.Control[1]);
            //throw new NotImplementedException();
        }

        public virtual void ShowText()
        {
            Settings.Instance.ProjectSettings.OnOpenProcedure(this, new OpenFormEventArgs(Text));
        }

        public virtual System.Windows.Forms.UserControl Show(System.Windows.Forms.Control[] controls)
        {
            if (_ucProcedure == null)
                _ucProcedure = new System.Windows.Forms.UserControl();// UserControls.ucShowProcedure(this);
            else
                _ucProcedure.Controls.Clear();
            List<System.Windows.Forms.Control> listcontrol = new List<System.Windows.Forms.Control>();
            System.Windows.Forms.Label label1 = new System.Windows.Forms.Label();
            label1.Text = string.Format("{0} - {1} - {2}", this.Name, this.Version, this.Type);
            label1.AutoEllipsis = true;
            label1.AutoSize = true;
            listcontrol.Add(label1);
            System.Windows.Forms.Label label2 = new System.Windows.Forms.Label();
            label2.Text = this.Hash;
            label2.AutoSize = true;
            listcontrol.Add(label2);
            System.Windows.Forms.ListBox list1 = new System.Windows.Forms.ListBox();
            list1.DataSource = this.ProcVersionList;
            list1.DoubleClick += new EventHandler(Version_DoubleClick);
            list1.Anchor |= System.Windows.Forms.AnchorStyles.Right;
            list1.Anchor |= System.Windows.Forms.AnchorStyles.Left;
            list1.Size = new System.Drawing.Size(_ucProcedure.Size.Width, list1.Size.Height);
            listcontrol.Add(list1);
            System.Windows.Forms.ListBox list2 = new System.Windows.Forms.ListBox();
            list2.DataSource = ActionInProcedure.ToString()
                  .Split(new[] { ", " }, StringSplitOptions.None)
                  .Select(v => (EnumActionInProcedure)Enum.Parse(typeof(EnumActionInProcedure), v)).ToList();
            list2.Size = new System.Drawing.Size(_ucProcedure.Size.Width, list2.Size.Height);
            list2.Anchor |= System.Windows.Forms.AnchorStyles.Right;
            list2.Anchor |= System.Windows.Forms.AnchorStyles.Left;
            listcontrol.Add(list2);
            
            System.Windows.Forms.Button bt1 = new System.Windows.Forms.Button();
            bt1.AutoSize = true;
            bt1.Text = "Refresh";
            bt1.Click += new EventHandler(bt1_Click);
            //tabcontrol[4]

            _ucProcedure.Controls.AddRange(listcontrol.ToArray());
            _ucProcedure.Controls.AddRange(controls);
            _ucProcedure.Controls.Add(bt1);

            System.Drawing.Point point = new System.Drawing.Point(0, 0);
            foreach (System.Windows.Forms.Control control in _ucProcedure.Controls)
            {
                control.Location = point;
                point.Y = point.Y + control.Size.Height;
            }
            //_ucProcedure.AutoSize = true;
            _ucProcedure.Size = new System.Drawing.Size(_ucProcedure.Size.Width, point.Y);

            return _ucProcedure;
        }

        void bt1_Click(object sender, EventArgs e)
        {
            GetInfoOfProcedure();
        }

        public virtual System.Windows.Forms.UserControl Show(IProcedure proc)
        {
            throw new NotImplementedException();
        }

        private void Version_DoubleClick(object sender, EventArgs e)
        {
            UserControls.EditProcedureVersion procVer = new UserControls.EditProcedureVersion((ProcedureVersion)((System.Windows.Forms.ListBox)sender).SelectedItem);

            System.Windows.Forms.Form tmpu = new System.Windows.Forms.Form();
            
            tmpu.AutoSize = true;
            tmpu.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            tmpu.Text = ((ProcedureVersion)((System.Windows.Forms.ListBox)sender).SelectedItem).Version;
            System.Windows.Forms.Button bt_OK = new System.Windows.Forms.Button();
            bt_OK.Text = "OK";
            bt_OK.Click += new EventHandler(bt_OK_Click);
            bt_OK.AutoSize = true;
            bt_OK.Location = new System.Drawing.Point(0, procVer.Size.Height);
            System.Windows.Forms.Button bt_Cancel = new System.Windows.Forms.Button();
            bt_Cancel.Text = "Cancel";
            bt_Cancel.Click += new EventHandler(bt_Cancel_Click);
            tmpu.CancelButton = bt_Cancel;
            bt_Cancel.AutoSize = true;
            bt_Cancel.Location = new System.Drawing.Point(bt_OK.Size.Width + 10, procVer.Size.Height);
            tmpu.Controls.Add(procVer);
            tmpu.Controls.Add(bt_Cancel);
            tmpu.Controls.Add(bt_OK);
            tmpu.Show();
            tmpu.FormClosing += new System.Windows.Forms.FormClosingEventHandler(tmpu_FormClosing);
            //((ProcedureVersion)((System.Windows.Forms.ListBox)sender).SelectedItem).Show();
        }

        private void bt_Cancel_Click(object sender, EventArgs e)
        {
            ((System.Windows.Forms.Form)((System.Windows.Forms.Control)sender).Parent).Close();
        }

        private void bt_OK_Click(object sender, EventArgs e)
        {
            bool close = true;
            var tmpo = (System.Windows.Forms.Form)((System.Windows.Forms.Control)sender).Parent;
            foreach (var a in tmpo.Controls)
            {
                Type b = a.GetType();
                if (a.GetType() == typeof(UserControls.EditProcedureVersion))
                {
                    close = ((UserControls.EditProcedureVersion)a).Save();
                }
            }
            if (close)
                tmpo.Close();
        }

        private void tmpu_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs e)
        {
            //var tmpo = (System.Windows.Forms.Form) sender;
            //foreach (var a in tmpo.Controls)
            //{
            //    Type b = a.GetType();
            //    if (a.GetType() == typeof(UserControls.EditProcedureVersion))
            //        ((UserControls.EditProcedureVersion)a).Save();
            //}
        }

        public void ChangeVersion(ProcedureVersion ProVer)
        {
            OnVersionChange(this, new VersionChangeEventArgs(_version, ProVer));
        }
        
        public static string GetMD5Hash(string pathName)
        {
            string strResult = "";
            string strHashData = "";

            byte[] arrbytHashValue;
            System.IO.FileStream oFileStream = null;

            System.Security.Cryptography.MD5CryptoServiceProvider oMD5Hasher = new System.Security.Cryptography.MD5CryptoServiceProvider();

            try
            {
                oFileStream = new System.IO.FileStream(pathName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite);
                arrbytHashValue = oMD5Hasher.ComputeHash(oFileStream);
                oFileStream.Close();

                strHashData = System.BitConverter.ToString(arrbytHashValue);
                strHashData = strHashData.Replace("-", "");
                strResult = strHashData;
            }
            catch (System.Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "Error!", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error, System.Windows.Forms.MessageBoxDefaultButton.Button1);
            }

            return (strResult);
        }

        public static string GetMD5Hash(FileStream file)
        {
            string strResult = "";
            string strHashData = "";

            byte[] arrbytHashValue;
            //System.IO.FileStream oFileStream = null;

            System.Security.Cryptography.MD5CryptoServiceProvider oMD5Hasher = new System.Security.Cryptography.MD5CryptoServiceProvider();

            try
            {
                //oFileStream = GetFileStream(pathName);
                arrbytHashValue = oMD5Hasher.ComputeHash(file);
                //oFileStream.Close();

                strHashData = System.BitConverter.ToString(arrbytHashValue);
                strHashData = strHashData.Replace("-", "");
                strResult = strHashData;
            }
            catch (System.Exception ex)
            {
                //System.Windows.Forms.MessageBox.Show(ex.Message, "Error!", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error, System.Windows.Forms.MessageBoxDefaultButton.Button1);
                throw ex;
            }

            return (strResult);
        }

        public static string GetMD5Hash(System.Security.Cryptography.MD5 md5Hash, string input)
        {

            // Convert the input string to a byte array and compute the hash.
            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

            // Create a new Stringbuilder to collect the bytes
            // and create a string.
            StringBuilder sBuilder = new StringBuilder();

            // Loop through each byte of the hashed data 
            // and format each one as a hexadecimal string.
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }

            // Return the hexadecimal string.
            return sBuilder.ToString();
        }

        public override string ToString()
        {
            return string.Format("{0}-{1} {2}", this.Name, this.Version, this.CreationTime.ToShortDateString());
        }

        public virtual string Serialize()
        {
            using (Stream str = new MemoryStream())
            {
                //System.Runtime.Serialization.Formatters.Binary.BinaryFormatter t = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(
                System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(Procedure));
                x.Serialize(str, this);
                using (StreamReader stmr = new StreamReader(str))
                {
                    return stmr.ReadToEnd();
                }
            }
        }

        public virtual T Deserialize<T>(string xmlobject)
            where T : class
        {
            byte[] byteArray = Encoding.ASCII.GetBytes(xmlobject);
            MemoryStream stream = new MemoryStream(byteArray);
            System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(T));
            T ip = (T)x.Deserialize(stream);
            return ip;
        }
        #endregion

        public virtual void Marge(Procedure procedure)
        {
            this.Source = procedure.Source + " Marge";
            this.CreationTime = procedure.CreationTime;
            this._hash = procedure.Hash;
            this.ListOfVariable = procedure.ListOfVariable;
            this.ModifiedTime = procedure.ModifiedTime;
            this.Name = procedure.Name;
            this.ProcVersionList = procedure.ProcVersionList;
            this.SourceType = procedure.SourceType;
            this.Text = procedure.Text;
            this.Type = procedure.Type;
            //this.Version = procedure.Version;
        }

        public void Start()
        {
            throw new NotImplementedException();
        }

        public virtual System.Xml.Schema.XmlSchema GetSchema()
        {
            throw new NotImplementedException();
        }

        public virtual void ReadXml(System.Xml.XmlReader reader)
        {
            if (ProcVersionList == null)
                ProcVersionList = new List<ProcedureVersion>();
            reader.MoveToContent();
            this.Name = reader.GetAttribute("Name");
            DateTime.TryParse(reader.GetAttribute("Creationtime"), out this._creationTime);
            DateTime.TryParse(reader.GetAttribute("Modifiedtime"), out this._modifiedtime);
            Enum.TryParse<EnumActionInProcedure>(reader.GetAttribute("ActionInProcedure"), out _actionInProcedure);
            Enum.TryParse<EnumProcType>(reader.GetAttribute("ActionInProcedure"), out _type);
            this._versionString = reader.GetAttribute("Version");
            this._hash = reader.GetAttribute("Hash");

            XmlDocument xmldoc = new XmlDocument();
            xmldoc.Load(reader);
            foreach (XmlNode rootnode in xmldoc.ChildNodes)
                foreach (XmlNode tmpNode in rootnode.ChildNodes)
                {
                    XmlReader r = new XmlNodeReader(tmpNode);
                    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(ProcedureVersion));
                    var obj = (Library.Objects.ProcedureVersion)Convert.ChangeType(serializer.Deserialize(r), typeof(ProcedureVersion));
                    obj.Parent = this;
                    _version = obj;
                    ProcVersionList.Add(obj);
                }
        }

        public virtual void WriteXml(System.Xml.XmlWriter writer)
        {
            writer.WriteAttributeString("Name", this.Name);
            writer.WriteAttributeString("Creationtime", this.CreationTime.ToUniversalTime().ToString());
            writer.WriteAttributeString("Modifiedtime", this.ModifiedTime.ToUniversalTime().ToString());
            writer.WriteAttributeString("ActionInProcedure", this._actionInProcedure.ToString());
            writer.WriteAttributeString("Type", this._type.ToString());
            writer.WriteAttributeString("Version", this._versionString);
            writer.WriteAttributeString("Hash", this._hash);

            var nsSerializer = new XmlSerializerNamespaces();
            nsSerializer.Add("", "");
            System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(_version.GetType(), "");
            xmlSerializer.Serialize(writer, _version, nsSerializer);
            //OriginalText="" Version="Unknown" User="" Project="NULL" Date="2011-11-22" Comment=""
            //writer.WriteAttributeString("OriginalText", this.Or
        }
    }
}
